﻿using System;
using System.Net;
using System.Windows.Controls;
using System.Windows.Media;
using MyStudioServerPlayer.MyStudioWs;
using System.ServiceModel;

using OpenLightGroup.Visualizers;
using OpenLightGroup.Visualizers.Controls;
using System.IO;
using System.Net.Browser;
using System.Windows.Threading;
using Saluse.MediaKit.IO;
using Saluse.MediaKit;

namespace MyStudioServerPlayer
{
    public partial class MainPage : UserControl
    {
        #region Global Variables

        public int intUserID;
        public string strPassword;
        public int intSongID;
        public string strSongPath;
        public string strSongOriginalName;

        private bool _AutoPlay;
        private string _Mp3File;
        private int _Visualization;
        private Saluse.MediaKit.RawMP3MediaStreamSource _mediaStreamSource = null;
        private SeekableStream _seekableStream = null;
        private DispatcherTimer _timer = null;

        #endregion

        #region MainPage
        public MainPage(string UserID, string SongID, string AutoPlay)
        {
            InitializeComponent();

            intUserID = Convert.ToInt32(UserID);
            intSongID = Convert.ToInt32(SongID);
            _AutoPlay = Convert.ToBoolean(AutoPlay);

            this.VisualizerOrchestrator.SoundBiteUpdated
                += new EventHandler(VisualizerOrchestrator_SoundBiteUpdated);

            GetSongInformation();
        }
        #endregion

        #region GetWebserviceAddress
        private string GetWebserviceAddress()
        {
            string strXapFile = @"/ClientBin/MyStudioServerPlayer.xap";
            string strBaseWebAddress = App.Current.Host.Source.AbsoluteUri.Replace(strXapFile, "");
            return strBaseWebAddress;
        }
        #endregion

        #region GetSongInformation
        private void GetSongInformation()
        {
            // *** Call a Web Service to get the File path and the Original Name
            WebServiceSoapClient MyStudioWs = new WebServiceSoapClient();
            EndpointAddress WebServiceEndpointAddress =
                new EndpointAddress(string.Format(@"{0}/Webservice/{1}", GetWebserviceAddress(), "WebService.asmx"));
            MyStudioWs.Endpoint.Address = WebServiceEndpointAddress;
            MyStudioWs.GetSongInformationCompleted += new EventHandler<GetSongInformationCompletedEventArgs>(MyStudioWs_GetSongInformationCompleted);
            MyStudioWs.GetSongInformationAsync(intUserID, intSongID);
        }

        void MyStudioWs_GetSongInformationCompleted(object sender, GetSongInformationCompletedEventArgs e)
        {
            try
            {
                // Show Song
                Initialize();
                SongInformation SongInformation = (SongInformation)e.Result;
                strSongPath = SongInformation.SongFileDirectory;
                strSongOriginalName = SongInformation.SongOriginalFileName.Replace(".mp3", ""); ;
                _Visualization = SongInformation.SongVisualizerID;

                Uri musicUri = new Uri(strSongPath, UriKind.Absolute);
                InitializeInternetMedia(strSongPath.ToString());
                SetVisualization(_Visualization);
            }
            catch
            {
                // Implement
            }
        }
        #endregion

        void VisualizerOrchestrator_SoundBiteUpdated(object sender, EventArgs e)
        {
            //Grab visualizer control and tell it to update...
            IVisualizer vis = (IVisualizer)this.VisualizerPanel.Child;

            vis.UpdateUI(this.VisualizerOrchestrator.CurrentSoundBite);
        }

        #region private methods

        private void Initialize()
        {
            _timer = new DispatcherTimer();
            _timer.Tick += new EventHandler(timer_Tick);
            _timer.Interval = TimeSpan.FromMilliseconds(200);

            // Set the defaults on the UI
            this.DataContext = this;
        }

        private void InitializeMedia(Stream mediaStream, string name, long mediaLength)
        {
            if (_mediaStreamSource != null)
            {
                Dispatcher.BeginInvoke(() =>
                {
                    _timer.Stop();
                    mediaElement.Stop();
                    mediaElement.Source = null;
                });

                _mediaStreamSource.Dispose();
                _mediaStreamSource = null;
            }

            _seekableStream = new SeekableStream(mediaStream, mediaLength);
            _mediaStreamSource = new RawMP3MediaStreamSource(_seekableStream);

            _mediaStreamSource.DownloadProgressChanged +=
                new Saluse.MediaKit.Delegates.DownloadProgressChangedDelegate(mediaStreamSource_DownloadProgressChanged);

            Dispatcher.BeginInvoke(() =>
            {
                this.VisualizerOrchestrator.MediaStream = _mediaStreamSource;
                mediaElement.SetSource(_mediaStreamSource);
                mediaElement.Volume = (double)1;
            });
        }

        private bool IsURLValid(string url)
        {
            //TODO: implement
            return true;
        }

        private void InitializeInternetMedia(string url)
        {
            if (IsURLValid(url))
            {
                Uri musicUri = new Uri(url);
                HttpWebRequest webRequest = (HttpWebRequest)WebRequestCreator.ClientHttp.Create(musicUri);
                webRequest.Method = "GET";
                // Important: AllowReadStreamBuffering must be set to False otherwise the WebRequest will download the entire file before firing the EndReponse event
                webRequest.AllowReadStreamBuffering = false;
                webRequest.BeginGetResponse(new AsyncCallback(HttpResponseCallback), webRequest);
            }
            else
            {
                //TODO:Display invalid URL message;
            }
        }

        private void HttpResponseCallback(IAsyncResult asynchronousResult)
        {
            HttpWebRequest webRequest = ((HttpWebRequest)(asynchronousResult.AsyncState));
            HttpWebResponse webResponse = ((HttpWebResponse)webRequest.EndGetResponse(asynchronousResult));
            Stream httpResponseStream = webResponse.GetResponseStream();

            InitializeMedia(
                httpResponseStream,
                System.IO.Path.GetFileName(webResponse.ResponseUri.LocalPath), //filename
                webResponse.ContentLength);
        }

        private string FormatTimeSpan(TimeSpan timeSpan)
        {
            return string.Format(
                "{0:00}:{1:00}",
                timeSpan.Minutes,
                timeSpan.Seconds);
        }

        #endregion

        #region private event handlers

        void timer_Tick(object sender, EventArgs e)
        {
            TimeSpan currentTime = _mediaStreamSource.Position;
            positionSlider.Value = currentTime.TotalMilliseconds;
            currentTimeTextBlock.Text = FormatTimeSpan(currentTime);
        }

        void mediaStreamSource_DownloadProgressChanged(object sender, double downloadProgress)
        {
            Dispatcher.BeginInvoke(() =>
            {
                positionSlider.ProgressPercentage = downloadProgress;
            });
        }

        private void toggleButton_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            switch (mediaElement.CurrentState)
            {
                case MediaElementState.Playing:
                    mediaElement.Pause();
                    break;

                case MediaElementState.Paused:
                case MediaElementState.Stopped:
                    mediaElement.Play();
                    break;
            }
        }

        private void stopButton_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            mediaElement.Stop();
        }

        private void mediaElement_CurrentStateChanged(object sender, System.Windows.RoutedEventArgs e)
        {
            switch (mediaElement.CurrentState)
            {
                case MediaElementState.Playing:
                    // On first load, media does not play,
                    // but ensure it auto plays thereafter is a better experience
                    if (!(mediaElement.AutoPlay))
                    {
                        mediaElement.AutoPlay = true;
                    }

                    toggleButton.Content = ";";
                    _timer.Start();
                    break;

                case MediaElementState.Closed:
                case MediaElementState.Paused:
                case MediaElementState.Stopped:
                    toggleButton.Content = "4";
                    _timer.Stop();
                    break;
            }
        }

        private void mediaElement_MediaOpened(object sender, System.Windows.RoutedEventArgs e)
        {
            TimeSpan durationTimeSpan = mediaElement.NaturalDuration.TimeSpan;
            durationTextBlock.Text = FormatTimeSpan(durationTimeSpan);
            positionSlider.Maximum = durationTimeSpan.TotalMilliseconds;

            // Start Media playing
            if (_AutoPlay)
            {
                mediaElement.Play();
            }
        }

        private void mediaElement_MediaEnded(object sender, System.Windows.RoutedEventArgs e)
        {
            _timer.Stop();
        }

        private void mediaElement_MediaFailed(object sender, System.Windows.ExceptionRoutedEventArgs e)
        {
            _timer.Stop();
            //TODO: Notify user of failure
        }

        private void positionSlider_SeekingStart(object sender, EventArgs e)
        {
            _timer.Stop();
        }

        private void positionSlider_SeekingEnd(object sender, EventArgs e)
        {
            if (mediaElement.CurrentState == MediaElementState.Playing)
            {
                _timer.Start();
            }
        }

        private void positionSlider_Changed(object sender, EventArgs e)
        {
            _mediaStreamSource.Position = TimeSpan.FromMilliseconds(positionSlider.Value);
        }

        private void SetVisualization(int visualDescription)
        {
            switch (visualDescription)
            {
                case 1:
                    PeakVisualizer bars = new PeakVisualizer();
                    this.VisualizerPanel.Child = bars;
                    break;
                case 2:
                    OrbsVisualizer orbs = new OrbsVisualizer();
                    this.VisualizerPanel.Child = orbs;
                    break;
                case 3:
                    SplotchVisualizer splotch = new SplotchVisualizer();
                    this.VisualizerPanel.Child = splotch;
                    break;
                default:
                    break;
            }

            //ToDo this is meant to be a placed holder for when we have params...
            ((IVisualizer)this.VisualizerPanel.Child).LoadParameters("one", 1);

        }

        #endregion
    }
}
